/*
 * @Author: liusheng
 * @Date: 2022-04-09 17:50:20
 * @LastEditors: liusheng
 * @LastEditTime: 2022-04-09 22:14:40
 * @Description: 剑指 Offer II 017. Minimum Window Substring
 * email:liusheng613@126.com
 * Copyright (c) 2022 by liusheng/liusheng, All Rights Reserved. 
 * 
 * 
 * 
  剑指 Offer II 017. 含有所有字符的最短字符串
给定两个字符串 s 和 t 。返回 s 中包含 t 的所有字符的最短子字符串。如果 s 中不存在符合条件的子字符串，则返回空字符串 "" 。
如果 s 中存在多个符合条件的子字符串，返回任意一个。
注意： 对于 t 中重复字符，我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。

示例 1：

输入：s = "ADOBECODEBANC", t = "ABC"
输出："BANC" 
解释：最短子字符串 "BANC" 包含了字符串 t 的所有字符 'A'、'B'、'C'
示例 2：

输入：s = "a", t = "a"
输出："a"
示例 3：

输入：s = "a", t = "aa"
输出：""
解释：t 中两个字符 'a' 均应包含在 s 的子串中，因此没有符合条件的子字符串，返回空字符串。
 

提示：

1 <= s.length, t.length <= 105
s 和 t 由英文字母组成
 

进阶：你能设计一个在 o(n) 时间内解决此问题的算法吗？

注意：本题与主站 76 题相似（本题答案不唯一）：https://leetcode-cn.com/problems/minimum-window-substring/
 
 */

#include <vector>
#include <string>
using namespace std;

class Solution {
public:
    //slide window solution
    string minWindow(string s, string t) {
        int n1 = s.size();
        int n2 = t.size();
        
        if(n2 > n1)
        {
            return string();
        }

        /*
        A-Z 26 character + 6 unused other character 
        in middle + 26 a-z
         */
        vector<int> cnt(58);
        for (int i = 0; i < n2; ++i)
        {
            --cnt[t[i] - 'A'];
        }

        int left = 0;
        int minLen = n1 + 1;
        int startPos = 0;
        for (int right = 0; right < n1; ++right)
        {
            ++cnt[s[right] - 'A'];
            //if length >= n2 and has covered all character in t
            //slide the left towards right
            while (right - left + 1 >= n2 && coverAllCharacter(cnt))
            {
                int len = right - left + 1;
                if (len < minLen)
                {
                    startPos = left;
                    minLen = len;
                }
                --cnt[s[left++] - 'A'];
            }
        }

        return minLen == n1 + 1 ? "" : s.substr(startPos,minLen);
    }

private:
    bool coverAllCharacter(vector<int> &cnt)
    {
        //traverse all elempent to find if 
        //every character in t has been covered
        for (int i = 0; i < 58; ++i)
        {
            if (cnt[i] < 0)
            {
                return false;
            }
        }

        return true;
    }
};

class Solution2 {
public:
    Solution2():cnt(58)
    {
        
    }
    
    string minWindow(string s, string t) {
        int n1 = s.size();
        int n2 = t.size();
        if (n2 > n1)
        {
            return string();
        }
        
        //'A' - 'Z' + 6 other + 'a' - 'z'
        for(int i = 0; i < n2; ++i)
        {
            --cnt[t[i] - 'A'];
        }
        
        int minLen = n1 + 1;
        int left = 0;
        int startPos = 0;

        //remaining character in t
        int remaining = n2;
        for (int right = 0; right < n1; ++right)
        { 
            //if after ++ cnt[right] still less than 0
            //than vover one character 
            if(++cnt[s[right] - 'A'] <= 0)
            {
                --remaining;
            }
            
            while (remaining == 0)
            {
                int len = right - left + 1;
                if ( len < minLen)
                {
                    minLen = len;
                    startPos = left;
                }
                
                //if after --cnt[left] the cnt < 0,then
                //this denote skip a character in t
                if (--cnt[s[left++] - 'A'] < 0)
                {
                    ++remaining;
                }
            }
        }
        
        return minLen == n1 + 1 ? string() : s.substr(startPos,minLen);
    }
    
private:
    vector<int> cnt;
};

//solution similar to the above
class Solution3 {
public:
    string minWindow(string s, string t) {
        int n1 = s.size();
        int n2 = t.size();
        
        if(n2 > n1)
        {
            return string();
        }

        /*
        A-Z 26 character + 6 unused other character 
        in middle + 26 a-z
         */
        vector<int> cnt(58);
        for (int i = 0; i < n2; ++i)
        {
            ++cnt[t[i] - 'A'];
        }

        int left = 0;
        int minLen = n1 + 1;
        int startPos = 0;
        int remaining = n2;
        for (int right = 0; right < n1; ++right)
        {
            if (--cnt[s[right] - 'A'] >= 0)
            {
                --remaining;
            }

            while (remaining == 0)
            {
                int len = right - left + 1;
                if (len < minLen)
                {
                    minLen = len;
                    startPos = left;
                }

                if (++cnt[s[left++] - 'A'] > 0)
                {
                    ++remaining;
                }
            } 
        }

        return minLen == n1 + 1 ? "" : s.substr(startPos,minLen);
    }
};

class Solution4 {
public:
    Solution4(): cnt(128) {}
    string minWindow(string s, string t) {
        int n1 = s.size();
        int n2 = t.size();
        
        if(n2 > n1)
        {
            return string();
        }

        /*
        A-Z 26 character + 6 unused other character 
        in middle + 26 a-z
         */
        
        for (int i = 0; i < n2; ++i)
        {
            ++cnt[t[i]];
        }

        int left = 0;
        int minLen = n1 + 1;
        int startPos = 0;
        int remaining = n2;
        for (int right = 0; right < n1; ++right)
        {
            if (--cnt[s[right]] >= 0)
            {
                --remaining;
            }

            while (remaining == 0)
            {
                int len = right - left + 1;
                if (len < minLen)
                {
                    minLen = len;
                    startPos = left;
                }

                if (++cnt[s[left++]] > 0)
                {
                    ++remaining;
                }
            } 
        }

        return minLen == n1 + 1 ? "" : s.substr(startPos,minLen);
    }

private:
    vector<int> cnt;
};